#ifndef __PERIODICFUNCTIONCALLER_H__ 
#define __PERIODICFUNCTIONCALLER_H__

#include "ThreadStarter.h"

inline uint32 GetMSTime() { return GetTickCount(); }

class CallbackBase {
public:
	virtual void Execute() {};
	virtual ~CallbackBase() {};
};

//the template classes for callback function with no arguments
template <class T>
class CallbackP0 : public CallbackBase
{
public:
	typedef void (T::*Method)();
	CallbackP0(T* _class_instance, Method _method)
	{
		_obj = _class_instance;
		_func = _method;//pointer to a member method of a class
	};
	void operator()(){ 
		return (_obj->*_func)();
	}
	void Execute(){ 
		return operator()(); 
	}

private:
	T*  _obj;
	Method  _func;//a member function pointer
};

template<class Type>
class NoArgPeriodicFunctionCaller : public ThreadBase
{
public:
	template<class T>
	NoArgPeriodicFunctionCaller(T* callback, 
		void (T::*method)(), //T::*method(member function pointer)
		uint32 Interval)
	{
		mCb = new CallbackP0<T>(callback, method);
		mInterval = Interval;
		mRunning = true;
	}

	~NoArgPeriodicFunctionCaller()
	{
		delete mCb;
		mCb	=	0;
	}

	bool Run()
	{
		mThread_active=true;
		//in the beginning , the event deactivated
		mEvent = CreateEvent(NULL, true, false, NULL);
		for(;;)
		{
			//wait for the event to be activated. if not,mInterval ms later, WaitForSingleObject
			//will return
			WaitForSingleObject(mEvent, mInterval);

			if(!mRunning)
				break;    

			//reset the event to be deactivated
			ResetEvent(mEvent);
			//execute the callback function
			mCb->Execute();
		}
		mThread_active=false;

		return false;
	}

	void Kill()
	{
		mRunning = false;

		//activate the event
		SetEvent(mEvent);

		while(mThread_active)
		{
			Sleep(100);
		}
	}

private:
	CallbackBase* mCb;
	uint32 mInterval;
	bool mRunning;
	bool mThread_active;
	HANDLE mEvent;
};

//template classes for callback with arguments
///////////////////////////////////////////////////////////////////////////
//template classes for callback with only 1 argument
template < class T, typename P1 >
class CallbackP1 : public CallbackBase
{
public:
	typedef void (T::*Method)(P1);
	CallbackP1(T* _class_instance, Method _method, P1 p1)
	{
		_obj = _class_instance;
		_func = _method;
		_p1 = p1;
	};

	void operator()() { return (_obj->*_func)(_p1); }
	void Execute() { return operator()(); }

private:

	T*  _obj;
	Method  _func;
	P1 _p1;
};

//template classes for callback with 2 arguments
template < class T, typename P1, typename P2 >
class CallbackP2 : public CallbackBase
{
public:

	typedef void (T::*Method)(P1, P2);
	CallbackP2(T* _class_instance, Method _method, P1 p1, P2 p2)
	{
		_obj = _class_instance;
		_func = _method;
		_p1 = p1;
		_p2 = p2;
	};

	void operator()() { return (_obj->*_func)(_p1, _p2); }
	void Execute() { return operator()(); }

private:
	T*  _obj;
	Method  _func;
	P1 _p1;
	P2 _p2;
};

//template classes for callback with 3 arguments
template < class T, typename P1, typename P2, typename P3 >
class CallbackP3 : public CallbackBase
{
public:

	typedef void (T::*Method)(P1, P2, P3);
	CallbackP3(T* _class_instance, Method _method, P1 p1, P2 p2, P3 p3)
	{
		_obj = _class_instance;
		_func = _method;
		_p1 = p1;
		_p2 = p2;
		_p3 = p3;
	};

	void operator()() { return (_obj->*_func)(_p1, _p2, _p3); }
	void Execute() { return operator()(); }

private:

	T*  _obj;
	Method  _func;
	P1 _p1;
	P2 _p2;
	P3 _p3;
};
//and so on


///////////////////////////////////////////////////////////////////////////
//the template class for user to use one-argument callback function
template<class T, class P1>
class PeriodicFunctionCaller : public ThreadBase
{
public:
	PeriodicFunctionCaller(T* callback, void (T::*method)(P1), P1 p1, uint32 Interval)
	{
		mCb = new CallbackP1<T,P1>(callback, method, p1);
		mInterval = Interval;
		mRunning = true;
	}

	~PeriodicFunctionCaller()
	{
		delete mCb;
		mCb	=	0;
	}

	bool Run()
	{
		mThread_active=true;

		//in the beginning , the event deactivated
		mEvent = CreateEvent(NULL, true, false, NULL);
		for(;;)
		{
			//wait for the event to be activated. if not,mInterval ms later, WaitForSingleObject
			//will return
			WaitForSingleObject(mEvent, mInterval);

			if(!mRunning)
				break;    

			//deactivate the event
			ResetEvent(mEvent);

			//execute the callback function
			mCb->Execute();
		}
		mThread_active=false;

		return false;
	}

	void Kill()
	{
		mRunning = false;

		//activate the event
		SetEvent(mEvent);

		while(mThread_active)
		{
			Sleep(100);
		}
	}

private:
	CallbackBase* mCb;
	uint32 mInterval;
	bool mRunning;
	bool mThread_active;
	HANDLE mEvent;
};

#endif//__PERIODICFUNCTIONCALLER_H__
